/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const path = require('path');
const fs = require('fs');
const ts = require('typescript');
const ExcelJS = require('exceljs');
const compressing = require('compressing');
const { readFile, getSubsystemBySyscap, getApiInfoWithFlag, getApiInfoDeleteDtsPath } = require('./util');
const { parse } = require('./collect_base_api');
const { allMergeData } = require('./format_data');
let methodType = '';

function getSubsystemJson(jsonDir) {
	let fileContent = fs.readFileSync(jsonDir, 'utf-8');
	let subsystems = JSON.parse(fileContent);
	const subsystemMap = new Map();
	const fileNameMap = new Map()
	subsystems.forEach(element => {
		subsystemMap.set(element.syscap, element.subsystem);
		fileNameMap.set(element.syscap, element.fileName)
	});
	return { subsystemMap, fileNameMap }
}

// 对比新旧版本文件列表
function compileFiles(newFiles, oldFiles) {
	const newFileNames = []
	const oldFileNames = []
	newFiles.forEach(file => {
		const fileName = path.basename(file).replace(/.d.ts$/g, '.ts')
		newFileNames.push(fileName)
	});
	oldFiles.forEach(file => {
		const fileName = path.basename(file).replace(/.d.ts$/g, '.ts')
		oldFileNames.push(fileName)
	});

	const compileApiInfos = []    //保存有差异的信息
	// 旧版本不存在新版本中的文件，表示新增
	newFileNames.forEach(fileName => {
		let index = oldFileNames.indexOf(fileName)
		if (index < 0) {
			compileApiInfos.push({
				flag: '新版本新增',
				fileName: fileName,
				filePath: newFiles[newFileNames.indexOf(fileName)]
			})
		}
	})
	// 新版本不在在旧版本中的文件，表示删除
	oldFileNames.forEach(fileName => {
		let index = newFileNames.indexOf(fileName)
		if (index < 0) {
			compileApiInfos.push({
				flag: '新版本删除',
				fileName: fileName,
				filePath: oldFiles[oldFileNames.indexOf(fileName)]
			})
		}
	})

	return compileApiInfos
}

// 根据文件列表获取api信息数组
function getFilesApi(files) {
	const fileContentList = []
	files.forEach(file => {
		let fileContent = fs.readFileSync(file, 'utf-8');
		fileContentList.push({
			fileName: path.basename(file).replace(/.d.ts$/g, '.ts'),
			fileContent: fileContent,
			fileRoot: file
		})

	});
	const api = parse(fileContentList);
	return api;
}

function getDIffApisWithCompile(newFiles, oldFiles) {
	const newFilesApi = getFilesApi(newFiles);
	const oldFilesApi = getFilesApi(oldFiles);
	// 去掉dtspath后的
	const tmpNewApis = []
	newFilesApi.forEach(newApi => {
		tmpNewApis.push(JSON.stringify(getApiInfoDeleteDtsPath(newApi)))
	})
	const tmpOldApis = []
	oldFilesApi.forEach(oldApi => {
		tmpOldApis.push(JSON.stringify(getApiInfoDeleteDtsPath(oldApi)))
	})

	let hasFunTypeNewApis = [];
	let hasFunTypeOldApis = [];
	hasFunTypeNewApis = deleteRepeatApi(tmpOldApis, tmpNewApis, newFilesApi, oldFilesApi).newDiffApiArr;
	hasFunTypeOldApis = deleteRepeatApi(tmpOldApis, tmpNewApis, newFilesApi, oldFilesApi).oldDiffApiArr;

	let newDiffApis = [];
	let oldDiffApis = [];
	newDiffApis = collectSameTypeFun(hasFunTypeNewApis);
	oldDiffApis = collectSameTypeFun(hasFunTypeOldApis);
	const subsystemMap = getSubsystemJson(subsystemDir).subsystemMap;
	const fileNameMap = getSubsystemJson(subsystemDir).fileNameMap;
	const diffApis = []
	getDiffApisBaseNew(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap);
	getDiffApisBaseOld(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap);
	return diffApis;
}

function deleteRepeatApi(oldApis, newApis, newFilesApi, oldFilesApi) {
	let newDiffApiArr = [];
	let oldDiffApiArr = [];
	for (let i = 0; i < newApis.length; i++) {
		const newApi = newApis[i];
		let index = oldApis.indexOf(newApi);
		if (index < 0) {
			let includeTypeApi = addMethodType(newFilesApi[i]);
			newDiffApiArr.push(includeTypeApi);
		}
	}

	for (let i = 0; i < oldApis.length; i++) {
		const oldApi = oldApis[i];
		let index = newApis.indexOf(oldApi);
		if (index < 0) {
			let includeTypeApi = addMethodType(oldFilesApi[i]);
			oldDiffApiArr.push(includeTypeApi);
		}
	}
	return { newDiffApiArr, oldDiffApiArr };
}

function collectSameTypeFun(apiArr) {
	apiArr.forEach(api => {
		let sameNameFun = '';
		let otherTypeMethodText = ''
		apiArr.forEach(newApi => {
			if (api.dtsPath.replace(newDir,'') === newApi.dtsPath.replace(newDir,'') && api.className === newApi.className &&
				api.methodName === newApi.methodName && api.apiType == 'Method' && api.funType === newApi.funType) {
				if (sameNameFun.indexOf(newApi.methodText) < 0 && api.funType === 'callback') {
					sameNameFun += `\n${newApi.methodText}`;
					api.callbackMethodText = sameNameFun;
				} else if (api.funType === 'Promise') {
					api.promiseMethodText = api.methodText;
				}else if (api.funType !== 'Promise' && api.funType !== 'callback') {
					otherTypeMethodText += `\n${newApi.methodText}`;
					api.otherTypeMethodText = otherTypeMethodText;
				}
			}
		})
	})
	return apiArr;
}

function addMethodType(baseApi) {
	let methodContent = `interface test{
              ${baseApi.methodText}
          }`;
	getMethodType(methodContent, filterType);
	if (methodType === 'callback' || methodType === 'Promise') {
		baseApi.funType = methodType;
	}
	return baseApi;
}

function getMethodType(content, callback) {
	ts.transpileModule(content, {
		compilerOptions: {
			"target": ts.ScriptTarget.ES2017
		},
		fileName: "index.ets",
		transformers: { before: [callback()] }
	})
}

function filterType() {
	return (context) => {
		methodType = '';
		return (node) => {
			getType(node);
			return node;
		}
		function getType(node) {
			// add function type(callback or Promise)
			if (ts.isFunctionDeclaration(node) || ts.isMethodSignature(node)) {
				getFunType(node);
			}
			return ts.visitEachChild(node, getType, context);
		}
	}
}

function getFunType(node) {
	if (node.type && ts.isTypeReferenceNode(node.type)) {
		methodType = node.type.typeName.escapedText;
	} else if (node.parameters.length > 0) {
		const parameter = node.parameters[node.parameters.length - 1];
		if (parameter.name.escapedText == 'callback') {
			methodType = parameter.name.escapedText;
		}
	} else {
		methodType = ''
	}
}

function collectDeprecatedDiff(newDeprecated, oldDeprecated, startDiffNew, startDiffOld, diffApis, subsystemMap,
	notes, fileNameMap, newApi) {
	flag = '废弃版本有变化';
	diffOld = startDiffOld + '废弃版本：' + oldDeprecated;
	const useinsteadInfo = newApi.useinsteadInfo instanceof Object ? newApi.useinsteadInfo.new : newApi.useinsteadInfo;
	if (newApi.useinsteadInfo) {
		diffNew = `${startDiffNew}废弃版本：${newDeprecated}\n代替接口：${useinsteadInfo}`;
	} else {
		diffNew = startDiffNew + '废弃版本：' + newDeprecated;
	}
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function getDiffApisBaseNew(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap) {
	const notes = ''
	newDiffApis.forEach(newApi => {
		let flag = ''
		let diffOld = 'NA';
		let diffNew = 'NA';
		const tmpApis = [];
		const diffMethodTextSet = new Set();
		oldDiffApis.forEach(oldApi => {
			if (newApi.dtsPath.replace(newDir,'') === oldApi.dtsPath.replace(oldDir,'')) {
				tmpApis.push(oldApi);
			}
		})
		if (tmpApis.length === 0) {
			collectNewFileApi(newApi, subsystemMap, notes, fileNameMap, diffApis, diffOld);
		} else {
			if (newApi.apiType == 'import') {
				collectImportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap);
			} else if (newApi.apiType == 'export') {
				collectExportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap);
			} else {
				let oldSameClassApis = handleApiByClassName(tmpApis, newApi, newDiffApis).oldSameClassApi;
				let oldMethodTexts = handleApiByClassName(tmpApis, newApi, newDiffApis).oldMethodTexts;
				let newSameClassApis = handleApiByClassName(tmpApis, newApi, newDiffApis).newSameClassApi;
				getNewAddApi(oldMethodTexts, newSameClassApis, diffApis, subsystemMap, fileNameMap);
				collectSameClassDiff(oldSameClassApis, newApi, diffNew, diffOld, diffApis, subsystemMap, fileNameMap, diffMethodTextSet);				
			}
		}
	})
}
function collectSameClassDiff(oldSameClassApis, newApi, diffNew, diffOld, diffApis, subsystemMap, fileNameMap, diffMethodTextSet) {
	const notes = '';
	if (oldSameClassApis.length === 0) {
		flag = '新增';
		if (newApi.methodName == '') {
			diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className;
		} else {
			diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className +
				'\n方法 or 属性：' + newApi.methodText;
		}
		let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
		diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap))
	} else {
		oldSameClassApis.forEach(oldApi => {
			if (newApi.methodName === oldApi.methodName && newApi.apiType.toString() === oldApi.apiType.toString()) {
				collectChangePart(newApi, oldApi, diffApis, subsystemMap, fileNameMap, diffMethodTextSet);				
			}
		})

	}
}
function getNewAddApi(oldMethodTexts, newSameClassApis, diffApis, subsystemMap, fileNameMap) {
	newSameClassApis.forEach(sameClassApi => {
		if (!oldMethodTexts.has(sameClassApi.methodText.replace(/\r|\n|\s+|\,|\;/g, ''))) {
			const notes = '';
			const flag = '新增';
			const diffNew = '类名：' + sameClassApi.className + '\n方法or属性：' + sameClassApi.methodText;
			const diffOld = 'NA';
			let sysCapInfo = getSubsystemBySyscap(sameClassApi, sameClassApi.sysCap);
			diffApis.push(getApiInfoWithFlag(sameClassApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap))
		}
	})
}
function collectChangePart(newApi, oldApi, diffApis, subsystemMap, fileNameMap, diffMethodTextSet) {
	let startDiffOld = ''
	let startDiffNew = ''
	if (newApi.methodName == '') {
		startDiffOld = '类名：' + oldApi.className + '\n'
		startDiffNew = '类名：' + newApi.className + '\n'
	} else {
		startDiffOld = '类名：' + oldApi.className + '\n方法 or 属性：' + oldApi.methodText + '\n'
		startDiffNew = '类名：' + newApi.className + '\n方法 or 属性：' + newApi.methodText + '\n'
	}
	if (isCallbackTypeFun(newApi, oldApi, 'callback')) {
		diffMethodTextSet.add(newApi.methodText);
		collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.callbackMethodText,
			oldApi.callbackMethodText, subsystemMap, fileNameMap);
	}
	if (isPromiseTypeFun(newApi, oldApi, 'Promise')) {
		diffMethodTextSet.add(newApi.methodText);
		collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.promiseMethodText,
			oldApi.promiseMethodText, subsystemMap, fileNameMap);
	}
	if (!newApi.funType && !oldApi.funType && newApi.methodText !== oldApi.methodText) {
		diffMethodTextSet.add(newApi.methodText);
		collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newApi.methodText,
			oldApi.methodText, subsystemMap, fileNameMap);
	}
	if (newApi.methodText === oldApi.methodText) {
		collectNoteDiff(newApi.version, oldApi.version, newApi.deprecated, oldApi.deprecated, newApi.errorCode,
			oldApi.errorCode, newApi.sysCap, oldApi.sysCap, newApi.isSystemApi, oldApi.isSystemApi, newApi.permission,
			oldApi.permission, newApi.model, oldApi.model, newApi.typeInfo, oldApi.typeInfo, startDiffNew, startDiffOld,
			diffApis, subsystemMap, fileNameMap, newApi);
	}

}
function isCallbackTypeFun(newApi, oldApi, funType) {
	if (newApi.funType === funType && oldApi.funType === funType &&
		newApi.callbackMethodText !== oldApi.callbackMethodText) {
		return true;
	} else {
		return false;
	}
}
function isPromiseTypeFun(newApi, oldApi, funType) {
	if (newApi.funType === funType && oldApi.funType === funType &&
		newApi.promiseMethodText !== oldApi.promiseMethodText) {
		return true;
	} else {
		return false;
	}
}

function collectNoteDiff(newVersion, oldVersion, newDeprecated, oldDeprecated, newErrorCode, oldErrorCode, newSyscap,
	oldSyscap, newIsSystemApi, oldIsSystemApi, newPermission, oldPermission, newModel, oldModel, newTypeInfo,
	oldTypeInfo, startDiffNew, startDiffOld, diffApis, subsystemMap, fileNameMap, newApi) {
	const notes = '';
	if (newVersion !== oldVersion) {
		collectVersionDiff(newVersion, oldVersion, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newDeprecated !== oldDeprecated) {
		collectDeprecatedDiff(newDeprecated, oldDeprecated, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newErrorCode !== oldErrorCode) {
		collectErrorCodeDiff(newErrorCode, oldErrorCode, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newSyscap !== oldSyscap) {
		collectSyscapDiff(newSyscap, oldSyscap, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newIsSystemApi !== oldIsSystemApi) {
		collectSystemApiDiff(newIsSystemApi, oldIsSystemApi, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newPermission !== oldPermission) {
		collectPermissionDiff(newPermission, oldPermission, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newModel !== oldModel) {
		collectModelDiff(newModel, oldModel, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
	if (newTypeInfo !== oldTypeInfo) {
		collectTypeDiff(newTypeInfo, oldTypeInfo, startDiffNew, startDiffOld,
			diffApis, subsystemMap, notes, fileNameMap, newApi);
	}
}

function collectTypeDiff(newType, oldType, startDiffNew, startDiffOld, diffApis, subsystemMap, notes, fileNameMap, newApi) {
	let flag = '';
	if (oldType !== newType) {
		flag = 'type有变化';
	}
	if (flag) {
		diffOld = startDiffOld + '起始版本：' + oldType;
		diffNew = startDiffNew + '起始版本：' + newType;
		let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
		diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
	}
}

function collectNewFileApi(newApi, subsystemMap, notes, fileNameMap, diffApis, diffOld) {
	flag = '新增'
	if (newApi.apiType === 'import') {
		diffNew = '模块名: ' + newApi.packageName + '\nimport 信息: ' + newApi.headimport
	} else if (newApi.apiType === 'export') {
		diffNew = '模块名: ' + newApi.packageName + '\nexport 信息: ' + newApi.endexport
	} else if (newApi.methodName === '') {
		diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className
	} else {
		diffNew = '模块名: ' + newApi.packageName + '\n类名: ' + newApi.className;+ '\n方法 or 属性: ' + newApi.methodText;
	}
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function collectImportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap) {
	const tmpApis2 = []
	tmpApis.forEach(oldApi => {
		if (oldApi.apiType == 'import' && newApi.headimport == oldApi.headimport) {
			tmpApis2.push(oldApi)
		}
	})

	if (tmpApis2.length == 0) {
		flag = '新增'
		diffNew = '模块名: ' + newApi.packageName + '\nimport 信息: ' + newApi.headimport
	}
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap))
}

function collectExportDiff(tmpApis, newApi, diffApis, subsystemMap, notes, fileNameMap) {
	const tmpApis3 = []
	tmpApis.forEach(oldApi => {
		if (oldApi.apiType == 'export' && newApi.endexport == oldApi.endexport) {
			tmpApis3.push(oldApi)
		}
	})
	if (tmpApis3.length == 0) {
		flag = '新增'
		diffNew = '模块名: ' + newApi.packageName + '\nexport 信息: ' + newApi.endexport
	}
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function handleApiByClassName(tmpApis, newApi, newDiffApis) {
	const oldSameClassApi = [];
	const newSameClassApi = []
	const oldMethodTexts = new Set([]);
	const newMethodTexts = new Set([]);
	let equalClassName = 'N/A';
	tmpApis.forEach(oldApi => {
		if (newApi.className === oldApi.className) {
			oldSameClassApi.push(oldApi);
			equalClassName = oldApi.className;
			oldMethodTexts.add(oldApi.methodText.replace(/\r|\n|\s+|\,|\;/g, ''));
		}
	})
	newDiffApis.forEach(apiText => {
		if (apiText.className == equalClassName) {
			newMethodTexts.add(apiText.methodText.replace(/\r|\n|\s+|\,|\;/g, ''));
			newSameClassApi.push(apiText);
		}
	})
	return { oldSameClassApi, oldMethodTexts, newMethodTexts, newSameClassApi };
}

function collectVersionDiff(newVersion, oldVersion, startDiffNew, startDiffOld, diffApis,
	subsystemMap, notes, fileNameMap, newApi) {
	flag = '起始版本有变化';
	diffOld = startDiffOld + '起始版本：' + oldVersion;
	diffNew = startDiffNew + '起始版本：' + newVersion;
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function collectModelDiff(newModel, oldModel, startDiffNew, startDiffOld, diffApis,
	subsystemMap, notes, fileNameMap, newApi) {
	flag = 'model有变化'
	diffOld = startDiffOld + 'model:' + oldModel
	diffNew = startDiffNew + 'model:' + newModel
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function collectPermissionDiff(newPermission, oldPermission, startDiffNew, startDiffOld, diffApis,
	subsystemMap, notes, fileNameMap, newApi) {
	flag = getPermissionFlag(oldPermission, newPermission);
	if (flag !== '格式变化') {
		diffOld = startDiffOld + '权限:' + oldPermission;
		diffNew = startDiffNew + '权限:' + newPermission;
		let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
		diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
	}
}

function collectMethodTextDiff(oldApi, newApi, startDiffNew, startDiffOld, diffApis, newMethodText, oldMethodText,
	subsystemMap, fileNameMap) {
	flag = getMethodFlag(oldMethodText, newMethodText);
	const note = '去重';
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	if (flag === '函数有变化') {
		diffOld = startDiffOld;
		diffNew = startDiffNew;
		diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, note, fileNameMap));
	}
}

function collectErrorCodeDiff(newErrorCode, oldErrorCode, startDiffNew, startDiffOld, diffApis, subsystemMap, notes,
	fileNameMap, newApi) {
	flag = oldErrorCode ? 'API修改(错误码)' : '新增(错误码)';
	if (flag === '新增(错误码)') {
		diffOld = 'NA';
	} else if (flag === 'API修改(错误码)') {
		diffOld = startDiffOld + '错误码内容：' + oldErrorCode;
	}
	diffNew = startDiffNew + '错误码内容:' + newErrorCode;
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function collectSyscapDiff(newSyscap, oldSyscap, startDiffNew, startDiffOld, diffApis, subsystemMap, notes,
	fileNameMap, newApi) {
	flag = 'SysCap有变化';
	diffOld = startDiffOld + 'SysCap:' + oldSyscap;
	diffNew = startDiffNew + 'SysCap:' + newSyscap;
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function collectSystemApiDiff(newIsSystemApi, oldIsSystemApi, startDiffNew, startDiffOld, diffApis, subsystemMap,
	notes, fileNameMap, newApi) {
	flag = '访问级别有变化';
	diffOld = startDiffOld + '访问级别：' + oldIsSystemApi;
	diffNew = startDiffNew + '访问级别：' + newIsSystemApi;
	let sysCapInfo = getSubsystemBySyscap(newApi, newApi.sysCap);
	diffApis.push(getApiInfoWithFlag(newApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
}

function getMethodFlag(methodTextOld, methodTextNew) {
	let methodTextOlds = methodTextOld.replace(/\r|\n|\s+|\,|\;/g, '');
	let methodTextNews = methodTextNew.replace(/\r|\n|\s+|\,|\;/g, '');
	if (methodTextOlds === methodTextNews) {
		return '函数格式变化';
	} else {
		return '函数有变化';
	}
}

function getPermissionFlag(permissionOld, permissionNew) {
	let permissionOlds = permissionOld.replace(/\r|\n|\s+|\.|\//g, '');
	let permissionNews = permissionNew.replace(/\r|\n|\s+|\.|\//g, '');
	if (permissionOlds === permissionNews) {
		return '格式变化';
	} else if (permissionOld == 'N/A') {
		return '新增(权限)';
	} else if (permissionNew == 'N/A') {
		return '删除(权限)';
	} else {
		return '权限有变化';
	}
}

function getDiffApisBaseOld(newDiffApis, oldDiffApis, diffApis, subsystemMap, fileNameMap) {
	const notes = ''
	oldDiffApis.forEach(oldApi => {
		let flag = '';
		let diffOld = '';
		let diffNew = 'NA';
		const tmpApis = [];
		newDiffApis.forEach(newApi => {
			if (oldApi.dtsPath.replace(oldDir,'') === newApi.dtsPath.replace(newDir,'')) {
				tmpApis.push(newApi);
			}
		})
		if (tmpApis.length === 0) {
			flag = deleteFileApi(oldApi, flag, diffOld).flag;
			diffOld = deleteFileApi(oldApi, flag, diffOld).diffOld;
		} else {
			if (oldApi.apiType === 'import') {
				flag = deleteImportApi(flag, diffOld, tmpApis, oldApi).flag;
				diffOld = deleteImportApi(flag, diffOld, tmpApis, oldApi).diffOld;
			} else if (oldApi.apiType === 'export') {
				flag = deleteExportApi(flag, diffOld, tmpApis, oldApi).flag;
				diffOld = deleteExportApi(flag, diffOld, tmpApis, oldApi).diffOld
			} else {
				flag = collectDeleteApis(tmpApis, oldApi, flag, diffOld).flag;
				diffOld = collectDeleteApis(tmpApis, oldApi, flag, diffOld).diffOld;
			}
		}
		if (flag !== '') {
			let sysCapInfo = getSubsystemBySyscap(oldApi, oldApi.sysCap);
			diffApis.push(getApiInfoWithFlag(oldApi, flag, diffOld, diffNew, subsystemMap, sysCapInfo, notes, fileNameMap));
		}
	})
}

function collectDeleteApis(tmpApis, oldApi, flag, diffOld) {
	const newSameClassApis = []
	tmpApis.forEach(newApi => {
		if (oldApi.className === newApi.className) {
			newSameClassApis.push(newApi);
		}
	})
	if (newSameClassApis.length === 0) {
		flag = '删除'
		if (oldApi.methodName == '') {
			diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className;
		} else {
			diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className + '\n方法 or 属性：' + oldApi.methodText;
		}
	} else {
		let count = 0;
		newSameClassApis.forEach(newApi => {
			if (oldApi.methodName === newApi.methodName && oldApi.apiType.toString() === newApi.apiType.toString()) {
				count++;
			}
		})

		if (count === 0) {
			flag = '删除'
			if (oldApi.methodName === '') {
				diffOld = '模块名：' + oldApi.packageName + '\n类名:' + oldApi.className;
			} else {
				diffOld = '模块名：' + oldApi.packageName + '\n类名:' + oldApi.className + '\n方法 or 属性:' + oldApi.methodText;
			}
		}
	}
	return { flag, diffOld };
}

function deleteImportApi(flag, diffOld, tmpApis, oldApi) {
	const tmpApis2 = []
	tmpApis.forEach(newApi => {
		if (newApi.apiType === 'import' && newApi.headimport === oldApi.headimport) {
			tmpApis2.push(newApi)
		}
	})

	if (tmpApis2.length === 0) {
		flag = '删除'
		diffOld = '模块名: ' + oldApi.packageName + '\nimport 信息: ' + oldApi.headimport
	}
	return { flag, diffOld };
}

function deleteExportApi(flag, diffOld, tmpApis, oldApi) {
	const tmpApis3 = [];
	tmpApis.forEach(newApi => {
		if (newApi.apiType === 'export' && newApi.endexport === oldApi.endexport) {
			tmpApis3.push(newApi);
		}
	})
	if (tmpApis3.length === 0) {
		flag = '删除';
		diffOld = '模块名: ' + oldApi.packageName + '\nexport 信息: ' + oldApi.endexport;
	}
	return { flag, diffOld };
}

function deleteFileApi(oldApi, flag, diffOld) {
	flag = '删除'
	if (oldApi.apiType === 'import') {
		diffOld = '模块名: ' + oldApi.packageName + '\nimport 信息: ' + oldApi.headimport
	} else if (oldApi.apiType === 'export') {
		diffOld = '模块名: ' + oldApi.packageName + '\nexport 信息: ' + oldApi.endexport
	} else if (oldApi.methodName === '') {
		diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className
	} else {
		diffOld = '模块名: ' + oldApi.packageName + '\n类名: ' + oldApi.className + '\n方法 or 属性：' + oldApi.methodText;
	}
	return { flag, diffOld };
}

// 输出新旧版本所有api对比结果
async function exportDiffApiInfo(exportType, compileApiInfos, exportFileName) {
	if (exportType == 'excel') {
		const workbook = new ExcelJS.Workbook();
		const sheet = workbook.addWorksheet('api差异', { viers: [{ xSplit: 1 }] });
		sheet.getRow(1).values = ['操作标记*', '差异项-旧版本', '差异项-新版本', 'd.ts文件', '归属子系统']
		for (let i = 0; i < compileApiInfos.length; i++) {
			let apiData = compileApiInfos[i];
			let fileName = apiData.dtsPath ? path.basename(apiData.dtsPath) : apiData.packageName;
			sheet.getRow(i + 2).values = [apiData.flag, apiData.diffOld, apiData.diffNew, fileName,
			apiData.subsystem];
		}
		const buffer = await workbook.xlsx.writeBuffer();
		fs.writeFile(exportFileName, buffer, function (err) {
			if (err) {
				return;
			}
		})
	} else if (exportType == 'json') {
		fs.writeFile(exportFileName, JSON.stringify(compileApiInfos), function (err) {
			if (err) {
				console.log('Write failed:' + err)
				return;
			}
			console.log(exportFileName + 'Write completed.')
		})
	}
}

function exportDiffMd(subsystem, diffInfos) {
	let finalContent = `| 操作 | 新版本 | 旧版本 | d.ts文件 |
| ---- | ------ | ------ | -------- |\n`
	for (let i = 0; i < diffInfos.length; i++) {
		let apiData = diffInfos[i];
		let fileName = apiData.dtsPath ? path.basename(apiData.dtsPath) : apiData.packageName;
		finalContent += `|${apiData.flag}|${apiData.diffOld.replace(/\r|\n/g, '<br>').replace(/\|/g, '\\|')}|` +
			`${apiData.diffNew.replace(/\r|\n/g, '<br>').replace(/\|/g, '\\|')}|${fileName}|\n`;
	}
	fs.writeFile(`../diff合集/js-apidiff-${subsystem}.md`, finalContent, function (err) {
		if (err) {
			console.log('WRITE FAILED:::', err);
			return;
		}
		console.log('WRITE SUCCESSED');
	})

}

function diffBySbusystem(compileApiInfos) {
	let filePath = __dirname.replace('\\src', '') + '\\subsystem.json';
	let subsystemArr = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
	let flagArr = ['新增', '删除', 'model有变化', '访问级别有变化', '废弃版本有变化', '起始版本有变化', '权限有变化',
		'删除(权限)', '新增(错误码)', '新增(权限)', '错误码有变化', '访问级别有变化', '函数有变化'];
	subsystemArr.forEach(subsystem => {
		let diffInfos = [];
		compileApiInfos.forEach(api => {
			if (subsystem.subsystem === api.subsystem) {
				diffInfos.push(api);
			}
		});
		if (diffInfos.length !== 0) {
			const sortDiffInfos = [];
			flagArr.forEach(flag => {
				diffInfos.forEach(diffInfo => {
					if (diffInfo.flag === flag) {
						sortDiffInfos.push(diffInfo)
					}
				})
			})
			exportDiffMd(subsystem.fileName, sortDiffInfos);
		}

	});
}
// 读取路径下所有的zip文件路径
function readZipFile(dir, zipFiles) {
	try {
		const files = fs.readdirSync(dir);
		files.forEach(element => {
			const filePath = path.join(dir, element);
			const status = fs.statSync(filePath);
			if (status.isDirectory()) {
				readZipFile(filePath, zipFiles);
			} else {
				if (filePath.endsWith('.zip')) {
					zipFiles.push(filePath);
				}
			}
		});
	} catch (error) {
		console.error('ETS ERROR:' + error)
	}
}

function unCompressAllZipFilesAndCompile(newDir, oldDir) {
	const zipFiles = []
	readZipFile(newDir, zipFiles)
	readZipFile(oldDir, zipFiles)
	let count = 0
	let countfile = 0
	zipFiles.forEach(async element => {
		let filePath = element.replace(path.basename(element), '')
		compressing.zip.uncompress(element, filePath).then((data) => {
			console.log("uncompress success:", data, '--' + element);
			count++;
			if ((count + countfile) == zipFiles.length) {
				compileAndExportToFile()
			}
		}).catch(error => {
			console.log(("uncompress error:", error))
		})
	});
}

function compileAndExportToFile() {
	const newFiles = []
	const oldFiles = []
	readFile(oldDir, oldFiles)
	readFile(newDir, newFiles)
	let diffApis = getDIffApisWithCompile(newFiles, oldFiles);
	let noRepeatDiffApi = [];
	let diffApisSet = new Set();
	diffApis.map(api => diffApisSet.add(JSON.stringify(api)));
	diffApisSet.forEach(item => {
		noRepeatDiffApi.push(JSON.parse(item))
	})
	for (let i = 0; i < allMergeData.length; i++) {
		for (let j = 0; j < noRepeatDiffApi.length; j++) {
			if (allMergeData[i].packageName === noRepeatDiffApi[j].packageName && noRepeatDiffApi[j].flag === '删除'
				&& allMergeData[i].diffOld === noRepeatDiffApi[j].methodText) {
				noRepeatDiffApi.splice(j, 1);
				j--;
			} else if (allMergeData[i].packageName === noRepeatDiffApi[j].packageName &&
				noRepeatDiffApi[j].flag === '新增' && allMergeData[i].diffNew === noRepeatDiffApi[j].methodText) {
				noRepeatDiffApi.splice(j, 1);
				j--;
			}

		}

	}
	let afterMergeData = noRepeatDiffApi.concat(allMergeData);
	exportDiffApiInfo('excel', afterMergeData, "Js_Api_Diff.xlsx")
	diffBySbusystem(afterMergeData);
}

const subsystemDir = __dirname.replace('\\src', '') + '\\subsystem.json';
const urlObject = fs.readFileSync(__dirname.replace('\\src', '') + '\\url.json', 'utf-8');
const oldDir = JSON.parse(urlObject).oldDir;
const newDir = JSON.parse(urlObject).newDir;
unCompressAllZipFilesAndCompile(newDir, oldDir)

